using System;

namespace EventReactor
{
    /// <summary>
    /// 进行注册/添加/加载后，方便进行移除的辅助结构
    /// </summary>
    public interface IRemove
    {
        void Add(Action act);
        void Remove();
    }
    public interface IEvent { }
    /// <summary>
    /// 同步事件，监听者只能进行同步操作
    /// </summary>
    public interface ISyncEvent : IEvent { }
    /// <summary>
    /// 异步事件，允许监听者进行异步操作
    /// </summary>
    public interface IAsyncEvent : IEvent
    {
        /// <summary>
        /// （在回调里使用）结束此次监听
        /// </summary>
        void EndCallback();
        EndMark Call { get; }
        EndMark End { get; }
        Action EndAct { get; set; }
    }
    /// <summary>
    /// 它允许按顺序执行。顺序执行确保各个监听者操作的逻辑顺序。适合需要等待各个依赖监听者依次完成的情景。
    /// </summary>
    public interface IOrderedAsyncEvent : IAsyncEvent, IMayReadOnly { }
    /// <summary>
    /// 它允许不按顺序执行。这种执行不会确保监听者操作的逻辑顺序。适合只需要等待所有监听者完成而不要求顺序的情景。
    /// </summary>
    public interface IWhenAllAsyncEvent : IAsyncEvent { }
    /// <summary>
    /// 标记着此次监听将以某种方式进行完成，可以安全进行下一步操作
    /// </summary>
    public class EndMark
    {
        private EndMark() { }
        private bool _async;
        public bool IsAsync => _async;

        public static EndMark End = new EndMark() { _async = false };
        public static EndMark Call = new EndMark() { _async = true };
    }
    /// <summary>
    /// 请求进行某种（有副作用）行为的异步事件
    /// </summary>
    public interface IRequest : IAsyncEvent
    {
        IResult Result { get; }
    }
    public interface IOrderedRequest : IRequest, IOrderedAsyncEvent { }
    public interface IWhenAllRequest : IRequest, IWhenAllAsyncEvent { }
    public interface IRequest<TResult> : IAsyncEvent where TResult : IResult, new()
    {
        IRequest AsIRequest { get; }
        TResult Result { get; }
    }
    public interface IOrderedRequest<TResult> : IRequest<TResult>, IOrderedAsyncEvent where TResult : IResult, new()
    {
        IOrderedRequest AsIOrderedRequest { get; }
    }
    public interface IWhenAllRequest<TResult> : IRequest<TResult>, IWhenAllAsyncEvent where TResult : IResult, new()
    {
        IWhenAllRequest AsIWhenAllRequest { get; }
    }
    public interface IMayReadOnly
    {
        /// <summary>
        /// 如果为true则不允许再修改
        /// </summary>
        bool IsReadOnly { get; }
        /// <summary>
        /// 标记其为ReadOnly的对象
        /// </summary>
        object ReadOnlyMarker { get; }
    }
    /// <summary>
    /// 某个请求结果的事件
    /// </summary>
    public interface IResult : ISyncEvent
    {
        bool IsSuccess { get; set; }
    }
    public interface IResult<T> : ISyncEvent
    {
        IResult AsIResult { get; }
        T MainValue { get; set; }
    }
    /// <summary>
    /// 进行某种（无副作用）查询的同步事件
    /// </summary>
    public interface IQuery : ISyncEvent, IMayReadOnly { }
    public interface IQuery<TValue>: ISyncEvent,IMayReadOnly
    {
        IQuery AsIQuery { get; }
        TValue MainValue { get; set; }
    }

    /// <summary>
    /// 事件总线
    /// </summary>
    public interface IEventBus
    {
        IRemove Listen(Type eventType, int priority, Func<object, IEvent, EndMark> callback);
        /// <summary>
        /// 发送一个同步事件。它将遍历所有监听者。
        /// </summary>
        bool TrySend(object sender, ISyncEvent evt, Action<ISyncEvent> onComplete);
        /// <summary>
        /// 发送一个允许异步操作的事件，确保逻辑顺序。它将遍历监听者，直到某个监听者发起异步操作时中断遍历。然后在异步操作的回调中继续遍历剩余监听者。
        /// </summary>
        bool TrySendOrdered(object sender, IOrderedAsyncEvent evt, Action<IOrderedAsyncEvent> onComplete);
        /// <summary>
        /// 发送一个允许异步操作的事件，不确保逻辑顺序。它将遍历监听者，但是不会中断遍历。直到所有监听者全部完成回调后结束。
        /// </summary>
        bool TrySendWhenAll(object sender, IWhenAllAsyncEvent evt, Action<IWhenAllAsyncEvent> onComplete);
    }
    public interface IModule
    {
        void OnListen(IModuleHubModuleListenView hub);
        void OnInit(IModuleHubModuleInitView hub, Action onEnd);
        void OnQuery(IModuleHubModuleQueryView hub);
        void OnDestroy();
    }
    /// <summary>
    /// 模块组中的模组将彼此视为依赖项
    /// </summary>
    public interface IModulePackage
    {
        string Key { get; }
        IRemove Add(IModule module);
        void OnInit(IModuleHubModulePackageView hub, Action onEnd);
        void OnDestroy();
    }
    /// <summary>
    /// 交互器（如UI、输入等）
    /// </summary>
    public interface IInteractor
    {
        IRemove OnInit(IModuleHubInteractorView hub, Action<IInteractor> onEnd);
        void OnDestroy();
    }
    /// <summary>
    /// 模块中心，负责管理各个模块的注册和卸载
    /// </summary>
    public interface IModuleHub
    {
        void OnInit(IModuleHubInitView hub,Action<IModuleHubAllView> onEnd);
        IRemove RuntimeAdd(object sourceScript, IModulePackage module, Action onEnd);
        void OnDestroy();
    }
    /// <summary>
    /// 模块中心的初始化视图。允许模块中心为自身添加模块和发送模块进度同步请求。此种权限在模块中心初始化时分发。
    /// </summary>
    public interface IModuleHubInitView
    {
        /// <summary>
        /// 添加的模块组不会被立即初始化。在所有基础模块组添加完后需要调用Start()开始初始化。
        /// </summary>
        IRemove Add(IModulePackage module);
        void Start(Action<IModuleHubAllView> onEnd);
    }
    public interface ICanListenSync
    {
        IRemove Listen<TSync>(int priority, Action<object, TSync> callback) where TSync : ISyncEvent;
    }
    public interface ICanListenAsync
    {
        IRemove Listen<TAsync>(int priority, Func<object, TAsync, EndMark> callback) where TAsync : IAsyncEvent;
    }
    public interface ICanSendRequest
    {
        /// <summary>
        /// 顺序发送一个异步请求
        /// </summary>
        bool TryRequestOrdered<TResult>(object sender, IOrderedRequest<TResult> evt, Action<TResult> onComplete = null) where TResult : IResult, new();
        /// <summary>
        /// 不要求顺序发送一个异步请求
        /// </summary>
        bool TryRequestWhenAll<TResult>(object sender, IWhenAllRequest<TResult> evt, Action<TResult> onComplete = null) where TResult : IResult, new();
    }
    public interface ICanQuery
    {
        /// <summary>
        /// 发送一个查询
        /// </summary>
        bool TryQuery<TQuery>(object sender, TQuery evt, Action<TQuery> onComplete) where TQuery : IQuery;
    }
    public interface ICanInitInteractor
    {
        /// <summary>
        /// 激活交互器
        /// </summary>
        IRemove Init(IInteractor interactor, Action<IInteractor> onComplete);
    }
    public interface IModuleHubModuleListenView: ICanListenSync,ICanListenAsync
    {
        IModuleHubAllView InListen(IEvent listenEnvironment);
    }
    public interface IModuleHubModuleInitView : ICanSendRequest,ICanInitInteractor { }
    public interface IModuleHubModuleQueryView : ICanQuery { }
    public interface IModuleHubModulePackageView : IModuleHubModuleListenView, IModuleHubModuleInitView, IModuleHubModuleQueryView { }
    public interface IModuleHubInteractorView : ICanQuery, ICanListenSync, ICanSendRequest { }
    public interface IModuleHubAllView : IModuleHubModulePackageView, IModuleHubInteractorView { }

    public static class IModuleHubExtensions
    {
        public static IRemove InitBy<TInteractor>(this TInteractor interactor,ICanInitInteractor view,Action<TInteractor> onComplete) where TInteractor:IInteractor
        {
            return view.Init(interactor,i=>onComplete?.Invoke((TInteractor)i));
        }
        public static TQuery QueryBy<TQuery>(this TQuery query, object sender, ICanQuery view) where TQuery : IQuery
        {
            view.TryQuery(sender, query, q=>query=q);
            return query;
        }
        public static bool Ordered<TResult>(this IOrderedRequest<TResult> request,object sender,ICanSendRequest view,Action<TResult> onComplete=null)where TResult:IResult,new()
        {
            return view.TryRequestOrdered(sender, request, onComplete);
        }
        public static T Value<T>(this IQuery<T> query,object sender, ICanQuery view)
        {
            T value = default;
            view.TryQuery(sender, query.AsIQuery, q=>
            {
                value = ((IQuery<T>)q).MainValue;
            });
            return value;
        }
    }
}
